﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Resources;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Linq;
using System.Linq;
using JuCloudy.Framework.Storge;

namespace JuCloudy.Platform.Structure
{
    public class XPackage
    {
        
        /// <summary>
        /// 从XAP包中返回程序集信息
        /// </summary>
        /// <param name="packageStream">Xap Stream</param>
        /// <returns>入口程序集</returns>
        public static Assembly LoadAssemblyFromXap(string AssemblyName)
        {
            /*using (System.IO.IsolatedStorage.IsolatedStorageFile file = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
            {*/
            using (Stream fileStream = /*new MemoryStream(LocalFile.Read("Application", "Xap", AssemblyName)))*/
                (Stream)JuCloudy.Framework.Storge.Session.Client["app_" + AssemblyName])
                {
                    #region Original Code
                    StreamResourceInfo sri = new StreamResourceInfo(fileStream, "application/binary");
                    Stream manifestStream = Application.GetResourceStream(sri, new Uri("AppManifest.xaml", UriKind.Relative)).Stream;
                    string appManifest = new StreamReader(manifestStream).ReadToEnd();
                    //Linq to xml
                    XElement deploymentRoot = XDocument.Parse(appManifest).Root;

                    List<XElement> deploymentParts = (from assemblyParts in deploymentRoot.Elements().Elements()
                                                      where assemblyParts.Name.LocalName.ToUpper()=="AssemblyPart".ToUpper()
                                                      select assemblyParts).ToList();
                   
                    Assembly asm = null;
                    foreach (XElement xElement in deploymentParts)
                    {
                        string source = xElement.Attribute("Source").Value;
                        AssemblyPart asmPart = new AssemblyPart();
                        asmPart.Source = source;
                        StreamResourceInfo streamInfo = Application.GetResourceStream(new StreamResourceInfo(fileStream, "application/binary"), new Uri(source, UriKind.Relative));
                        if (source.Contains( AssemblyName + ".dll"))
                        {
                            asm = asmPart.Load(streamInfo.Stream);
                        }
                        else
                        {
                            asmPart.Load(streamInfo.Stream);
                        }
                    }
                    return asm;
               /* }*/
            }

            #endregion

        }

        /// <summary>
        /// 从XAP包中返回程序集信息
        /// </summary>
        /// <param name="packageStream">Xap Stream</param>
        /// <returns>入口程序集</returns>
        public static Assembly LoadAssembly(string AssemblyName)
        {
            var packageStream=(Stream)JuCloudy.Framework.Storge.Session.Client["app_" + AssemblyName];
            // 加载AppManifest.xaml
            var streamResourceInfo = new StreamResourceInfo(packageStream, null);
            Stream stream = Application.GetResourceStream(streamResourceInfo, new Uri("AppManifest.xaml", UriKind.Relative)).Stream;
            XmlReader xmlReader = XmlReader.Create(stream);

            // 读取程序集信息
            Assembly entryAssembly = null;
            string entryAssemblyName = string.Empty;
            var assemblyPartInfos = new List<AssemblyPartInfo>();
            while (xmlReader.Read())
            {
                switch (xmlReader.NodeType)
                {
                    case XmlNodeType.Element:
                        if (xmlReader.Name == "Deployment")
                        {
                            // 入口程序集名称
                            entryAssemblyName = xmlReader.GetAttribute("EntryPointAssembly");
                        }
                        else if (xmlReader.Name == "AssemblyPart")
                        {
                            var name = xmlReader.GetAttribute("x:Name");
                            var source = xmlReader.GetAttribute("Source");

                            assemblyPartInfos.Add(new AssemblyPartInfo { Name = name, Source = source });
                        }
                        break;
                    default:
                        break;
                }
            }

            var assemblyPart = new AssemblyPart();
            streamResourceInfo = new StreamResourceInfo(packageStream, "application/binary");
            // 加载程序集
            foreach (var assemblyPartInfo in assemblyPartInfos)
            {
                var assemblyUri = new Uri(assemblyPartInfo.Source, UriKind.Relative);
                StreamResourceInfo streamInfo = Application.GetResourceStream(streamResourceInfo, assemblyUri);

                // 入口程序集
                if (assemblyPartInfo.Name == entryAssemblyName)
                {
                    entryAssembly = assemblyPart.Load(streamInfo.Stream);
                }
                // 其他程序集
                else
                {
                    assemblyPart.Load(streamInfo.Stream);
                }
            }

            return entryAssembly;
        }
    }

    public class AssemblyPartInfo
    {
        public string Name { get; set; }

        public string Source { get; set; }
    }
}
